/**
 * @brief 文件句柄管理类的实现
 * @details 只管理socket,记录fd是否为socket，用户是否设置非属性,系统是否设置非属性，sen/recv超时时间
 * 提供FdManager单例和get/del方法,用户创建/获取/删除fd
 */

#include "fd_manager.h"
#include "hook.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

// Done

// 初始化
bool FdCtx::init()
{
    if (m_isInit)
        return true;

    m_recvTimeout = -1;
    m_sendTimeout = -1;

    struct stat fd_stat;
    if (-1 == fstat(m_fd, &fd_stat))
    {
        m_isInit = false;
        m_isSocket = false;
    }
    else
    {
        m_isInit = true;
        m_isSocket = S_ISSOCK(fd_stat.st_mode);
    }

    if (m_isSocket)
    {
        // 添加非阻塞属性
        int flags = fcntl(m_fd, F_GETFL, 0);
        if (!(flags & O_NONBLOCK))
        {
            fcntl(m_fd, F_SETFL, flags | O_NONBLOCK);
            m_sysNonblock = true;
        }
    }
    else
        m_sysNonblock = false;

    m_userNonblock = false;
    m_isClosed = false;
    return m_isInit;
}

FdCtx::FdCtx(int fd)
    : m_isInit(false), m_isSocket(false), m_sysNonblock(false), m_userNonblock(false), m_isClosed(false), m_fd(fd), m_recvTimeout(-1), m_sendTimeout(-1)
{
    init();
}

FdCtx::~FdCtx()
{
}

// 设置超时时间
// type SO_RECVTIMEO(读超时) SO_SENDTIMEO(写超时)
void FdCtx::setTimeout(int type, uint64_t timeout)
{
    if (type == SO_RCVTIMEO)
        m_recvTimeout = timeout;
    else
        m_sendTimeout = timeout;
}

// 获取超时时间
uint64_t FdCtx::getTimeout(int type)
{
    if (type == SO_RCVTIMEO)
        return m_recvTimeout;
    else
        return m_sendTimeout;
}

FdManager::FdManager()
{
    m_datas.resize(64);
}

FdCtx::ptr FdManager::get(int fd, bool auto_create)
{
    if (fd == -1)
        return nullptr;

    RWMutexType::ReadLock lock(m_mutex);
    if ((int)m_datas.size() <= fd)
    {
        if (auto_create == false)
        {
            return nullptr;
        }
    }
    else
    {
        if (m_datas[fd] || !auto_create)
        {
            return m_datas[fd];
        }
    }
    lock.unlock();

    RWMutexType::WriteLock lock2(m_mutex);
    FdCtx::ptr ctx(new FdCtx(fd));
    if (fd >= (int)m_datas.size())
    {
        m_datas.resize(fd * 1.5);
    }

    m_datas[fd] = ctx;
    return ctx;
}

// 删除文件句柄
void FdManager::del(int fd)
{
    RWMutexType::WriteLock lock(m_mutex);
    if ((int)m_datas.size() <= fd)
        return;
    m_datas[fd].reset();
}